package web

import (
	"commerce/cache"
	"commerce/common"
	"commerce/data"
	"commerce/req"
	"commerce/utils"
	"commerce/vo"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"sync"
)

/* 此文件是 app 购物车 请求 */

func CountGoods(w http.ResponseWriter, r *http.Request) {

	var res vo.CartGoodsVo
	var count = 0

	tokenHeader := r.Header["Token"]
	if tokenHeader != nil && len(tokenHeader) > 0 {

		appUser, err := parseAppToken(tokenHeader[0])
		// 用户登录了
		if err == nil && appUser != nil {
			count, err = data.GetCartGoodsCount(appUser.Mid)
			if err != nil {
				common.Error.Println("CountGoods(cart) err:", err)
			}
		}
	}
	res.CartTotal = vo.CartTotalVo{GoodsCount: count}

	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func AddToCart(w http.ResponseWriter, r *http.Request) {

	var cartReq req.AddToCartReq
	err := json.NewDecoder(r.Body).Decode(&cartReq)
	if err != nil {
		common.Error.Printf("AddToCart err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	member := extractUserFromContext(r)
	if member == nil {
		common.DisplayTokenErr(w, http.StatusUnauthorized)
		return
	}
	_, err = data.AddToCart(member.Mid, cartReq.SkuId, cartReq.Number)
	if err != nil {
		common.Error.Printf("2.AddToCart err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	count, err := data.GetCartGoodsCount(member.Mid)
	if err != nil {
		common.Error.Println("AddToCart->GetCartGoodsCount err:", err)
	}
	j, _ := json.Marshal(vo.Ok(count))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func CartIndex(w http.ResponseWriter, r *http.Request) {

	member := extractUserFromContext(r)
	if member == nil || member.Mid <= 0 {
		common.DisplayTokenErr(w, http.StatusUnauthorized)
		return
	}
	cart, err := data.GetCart(member.Mid)

	if err != nil {
		common.Error.Printf("CartIndex err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	j, _ := json.Marshal(vo.Ok(cart))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func SelectCartItemOrNot(w http.ResponseWriter, r *http.Request) {

	var checkReq req.CartCheckReq
	err := json.NewDecoder(r.Body).Decode(&checkReq)
	if err != nil {
		common.Error.Printf("SelectCartItemOrNot err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	if checkReq.SkuId <= 0 && len(checkReq.SkuIds) == 0 || checkReq.IsChecked != 0 && checkReq.IsChecked != 1 {
		common.Error.Println("2.SelectCartItemOrNot err:参数非法")
		j, _ := json.Marshal(vo.Err("参数非法！"))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		w.Write(j)
		return
	}
	member := extractUserFromContext(r)
	if member == nil || member.Mid <= 0 {
		common.DisplayTokenErr(w, http.StatusUnauthorized)
		return
	}
	// 单个操作
	if checkReq.SkuId > 0 {
		err = data.CheckItem(member.Mid, checkReq.SkuId, checkReq.IsChecked == 1)
	} else {
		checked := checkReq.IsChecked == 1
		var skuId int
		// 全选操作
		for _, skuIdStr := range strings.Split(checkReq.SkuIds, ",") {

			skuId, err = strconv.Atoi(skuIdStr)
			if err != nil {
				continue
			}
			err = data.CheckItem(member.Mid, skuId, checked)
			if err != nil {
				break
			}
		}
	}
	if err != nil {
		common.Error.Printf("3.SelectCartItemOrNot err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		w.Write(j)
		return
	}
	cart, err := data.GetCart(member.Mid)

	if err != nil {
		common.Error.Printf("4.SelectCartItemOrNot err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	j, _ := json.Marshal(vo.Ok(cart))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func UpdateCartItemCount(w http.ResponseWriter, r *http.Request) {

	skuId, err := strconv.Atoi(r.PostFormValue("skuId"))
	if err != nil {
		common.Error.Printf("1.UpdateCartItemCount err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	count, err := strconv.Atoi(r.PostFormValue("count"))
	if err != nil {
		common.Error.Printf("2.UpdateCartItemCount err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	if skuId <= 0 || count <= 0 {
		common.Error.Printf("3.UpdateCartItemCount err:参数非法")
		j, _ := json.Marshal(vo.Err("参数非法！"))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		w.Write(j)
		return
	}
	member := extractUserFromContext(r)
	if member == nil || member.Mid <= 0 {
		common.DisplayTokenErr(w, http.StatusUnauthorized)
		return
	}
	err = data.UpdateCartItemCount(member.Mid, skuId, count)
	if err != nil {
		common.Error.Printf("4.UpdateCartItemCount err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	j, _ := json.Marshal(vo.Ok(nil))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func DeleteCartItems(w http.ResponseWriter, r *http.Request) {

	var deleteReq req.CartItemsDeleteReq
	err := json.NewDecoder(r.Body).Decode(&deleteReq)
	if err != nil {
		common.Error.Printf("DeleteCartItems err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	if len(deleteReq.SkuIds) == 0 {
		common.Error.Println("2.DeleteCartItems err:参数非法！")
		j, _ := json.Marshal(vo.Err("参数非法！"))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		w.Write(j)
		return
	}
	member := extractUserFromContext(r)
	if member == nil || member.Mid <= 0 {
		common.DisplayTokenErr(w, http.StatusUnauthorized)
		return
	}
	var skuId int
	for _, skuIdStr := range strings.Split(deleteReq.SkuIds, ",") {

		skuId, err = strconv.Atoi(skuIdStr)
		if err != nil {
			continue
		}
		err = data.DeleteCartItem(member.Mid, skuId)
		if err != nil {
			break
		}
	}
	if err != nil {
		common.Error.Printf("3.DeleteCartItems err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		w.Write(j)
		return
	}
	cart, err := data.GetCart(member.Mid)

	if err != nil {
		common.Error.Printf("4.DeleteCartItems err:%v", err)
		j, _ := json.Marshal(vo.Err(err.Error()))
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write(j)
		return
	}
	j, _ := json.Marshal(vo.Ok(cart))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func CheckOut(w http.ResponseWriter, r *http.Request) {

	addressId, _ := strconv.Atoi(r.PostFormValue("addressId"))
	couponId, _ := strconv.Atoi(r.PostFormValue("couponId"))
	// 0-直接购买，1-购物车
	buyType, _ := strconv.Atoi(r.PostFormValue("type"))

	member := extractUserFromContext(r)
	if member == nil || member.Mid <= 0 {
		common.DisplayTokenErr(w, http.StatusUnauthorized)
		return
	}
	if buyType == 1 {
		checkOutCart(w, member, addressId, couponId)
	} else {
		// 直接购买
		checkOutBuyCart(w, member, addressId, couponId)
	}
}

func checkOutCart(w http.ResponseWriter, member *AppUser, addressId int, couponId int) {

	// @ todo 暂时不接入卡券
	if couponId > 0 {
	}
	var res vo.CheckoutCartVo

	var wg sync.WaitGroup
	wg.Add(2)

	// 收获地址
	go func() {
		defer wg.Done()
		res.FreightPrice = 0
		if addressId > 0 {
			addr, err := data.GetMemberReceiveAddrById(addressId)
			if err == nil && addr != nil {
				res.CheckedAddress = vo.CheckedAddrVo{Id: addressId, Name: addr.Name, TelNumber: addr.Phone,
					IsDefault: addr.DefaultStatus, DetailInfo: addr.DetailAddr,
					FullRegion: fmt.Sprintf("%s/%s/%s", addr.Province, addr.City, addr.Region)}
			}
			// 查询运费 @ todo
			res.FreightPrice = 5
		}
	}()
	// 购物项
	go func() {
		defer wg.Done()
		cart, err := data.ListCheckedItems(member.Mid)
		if err == nil && cart != nil {
			res.CheckedGoodsList = cart.CartItems
			res.GoodsTotalPrice = cart.CartTotal.CheckedGoodsAmount
		}
	}()

	// 防重令牌
	orderToken := utils.Uuid()
	cache.SetWithTTL(common.ORDER_TOKEN_PREFIX+strconv.Itoa(member.Mid), orderToken, 30*60)
	res.OrderToken = orderToken

	wg.Wait()

	actualPrice := res.GoodsTotalPrice + res.FreightPrice
	actualPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", actualPrice), 64)
	res.ActualPrice = actualPrice
	res.OrderTotalPrice = actualPrice

	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func checkOutBuyCart(w http.ResponseWriter, member *AppUser, addressId int, couponId int) {

	// @ todo 暂时不接入卡券
	if couponId > 0 {
	}
	var res vo.CheckoutCartVo

	var wg sync.WaitGroup
	wg.Add(2)

	// 收获地址
	go func() {
		defer wg.Done()
		res.FreightPrice = 0
		if addressId > 0 {
			addr, err := data.GetMemberReceiveAddrById(addressId)
			if err == nil && addr != nil {
				res.CheckedAddress = vo.CheckedAddrVo{Id: addressId, Name: addr.Name, TelNumber: addr.Phone,
					IsDefault: addr.DefaultStatus, DetailInfo: addr.DetailAddr,
					FullRegion: fmt.Sprintf("%s/%s/%s", addr.Province, addr.City, addr.Region)}
			}
			// 查询运费 @ todo
			res.FreightPrice = 5
		}
	}()
	// 购物项
	go func() {
		defer wg.Done()
		cart, err := data.ListBuyCheckedItems(member.Mid)
		if err == nil && cart != nil {
			res.CheckedGoodsList = cart.CartItems
			res.GoodsTotalPrice = cart.CartTotal.CheckedGoodsAmount
		}
	}()
	// 防重令牌
	orderToken := utils.Uuid()
	cache.SetWithTTL(common.ORDER_TOKEN_PREFIX+strconv.Itoa(member.Mid), orderToken, 30*60)
	res.OrderToken = orderToken

	wg.Wait()

	actualPrice := res.GoodsTotalPrice + res.FreightPrice
	actualPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", actualPrice), 64)
	res.ActualPrice = actualPrice
	res.OrderTotalPrice = actualPrice

	j, _ := json.Marshal(vo.Ok(res))
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(j)
}

func extractUserFromContext(r *http.Request) *AppUser {

	appUser := r.Context().Value(APP)

	if appUser == nil {
		return nil
	}
	member, ok := appUser.(*AppUser)
	if !ok {
		return nil
	}
	return member
}
